#ifndef WEATHER_H
#define WEATHER_H

#include <inttypes.h>

#define DAWN_DUSK_OFFSET 90U   // How sooner should blue lights come up before white, and how later should they go off after white
#define TIME_OFFSET 120U

#define SHORT_CLOUD 0
#define LONG_CLOUD 1
#define THUNDERSTORM_CLOUD 10
#define NO_CLOUD 255           // Special index value to inform not inside cloud


// Maximum number of clouds defined at once, limited by Arduino memory
#define MAXCLOUDS 10
#define SHORT_CLOUD_POINTS 9
#define LONG_CLOUD_POINTS 16
#define THUNDERSTORM_SHAPE_POINTS 7
#define BASICDAYCURVESIZE 14


class Weather
{
public:
	
	// Definition of a cloud
	struct Cloud 
	{
		unsigned int start;
		unsigned int type;
	};

	// Definition of a light waypoint
	struct Waypoint 
	{
		unsigned int time;   // in 2 seconds, 1h=900 2secs, 24h = 43200 2secs
		float        level;
	};

	// Definition of a segment
	struct Segment 
	{
		unsigned int strTime;  // Start
		float        strLevel;  // Start
		unsigned int finTime;  // Finish
		float        finLevel;  // Finish
	};


	Weather(float maxWhite, float maxBlue);

	void planNewDay(uint8_t aMonth, uint8_t aDay);
	void planNextCloudBatch(unsigned int now);
	void planBasicCurve(uint8_t aMonth, uint8_t aDay);

	void getLevel(unsigned int now, bool& inThunderstorm, float& whiteLevel, float& blueLevel);

	void changeOkta(uint8_t okta);
	void dumpCurve();
  
private:

	// Cloud shape curve
	static const Waypoint m_shortCloud[SHORT_CLOUD_POINTS];

	// Cloud shape curve
	static const Waypoint m_longCloud[LONG_CLOUD_POINTS];

	// Thunderstorm cloud shape curve
	static const Waypoint m_thunderstormCloud[THUNDERSTORM_SHAPE_POINTS];

	Waypoint m_dcwWhiteCurve[BASICDAYCURVESIZE];
	Waypoint m_dcwBlueCurve[BASICDAYCURVESIZE];

	// So for January 1-15 was clear, so 16-60 was cloudy and 61-100 would be mixed. 
	static const uint8_t m_clearDays[12];    // From 0 to clearDays = clear day (oktas 0..1)
	static const uint8_t m_cloudyDays[12];   // From clearDays to cloudyDays = cloudy day (oktas 4..8)
	// From cloudyDays to 100 = mixed day (oktas 2..3)

	// Month Data for Start, Stop, Photo Period and Fade (based off of actual times, best not to change)
	//Days in each month
	static const uint8_t m_daysInMonth[12];  

	// Minimum and Maximum sunrise start times in each month
	static const unsigned int m_minSunriseStart[12]; 
	static const unsigned int m_maxSunriseStart[12]; 

	// Minimum and Maximum sunset stop times each month
	static const unsigned int m_minSunsetFinish[12]; 
	static const unsigned int m_maxSunsetFinish[12]; 

	// Minimum and Maximum sunrise or sunset fade duration in each month
	static const unsigned int m_minFadeDuration[12]; 
	static const unsigned int m_maxFadeDuration[12]; 
	
	Cloud m_clouds[MAXCLOUDS];

	uint8_t m_qtyClouds;       // How many clouds do we have active now in the array?
	float m_maxWhite;
	float m_maxBlue;

	uint8_t m_okta;

	String m_forecast;
	unsigned int m_cloudSpacing;
	uint8_t m_cloudType1;
	uint8_t m_cloudType2;

	unsigned int m_currCloudCoverStart;
	unsigned int m_currCloudCoverFinish;

	void setCloudSpacingAndTypes();

	void getCloudSegment(uint8_t cloudIndex, uint8_t cloudSegIndex, 
		unsigned int& strTime, float& strLevel, unsigned int& finTime, float& finLevel,
		unsigned int& bStrTime, float& bStrLevel, unsigned int& bFinTime, float& bFinLevel);

	void getSegment(unsigned int when, 
		unsigned int& wStrTime, float& wStrLevel, unsigned int& wFinTime, float& wFinLevel,
		unsigned int& bStrTime, float& bStrLevel, unsigned int& bFinTime, float& bFinLevel);

	unsigned int getCloudDuration(uint8_t type);
	uint8_t insideCloud(unsigned int now);

};

#endif
